﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using EnvDTE;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Project;
using Microsoft.VisualStudio.Project.Automation;
using Microsoft.WowAddonStudio.Project.Automation;
using Microsoft.WowAddonStudio.ProjectRefactor;

namespace Microsoft.WowAddonStudio.Project
{
	/// <summary>
	/// An object that deals with user interaction via a GUI in the form a hierarchy: a parent node with zero or more child nodes, each of which
	/// can itself be a hierarchy.  
	/// </summary>
	[ComVisible(true)]
	public class WowFileNode : FileNode
	{
		protected OAWowFileItem automationObject;

		/// <summary>
		/// Initializes a new instance of the <see cref="WowFileNode"/> class.
		/// </summary>
		/// <param name="root">The root.</param>
		/// <param name="e">The e.</param>
		public WowFileNode(ProjectNode root, ProjectElement e)
			: base(root, e)
		{
		}

		/// <summary>
		/// Returs a Wow FileNode specific object implmenting DTE.ProjectItem
		/// </summary>
		/// <returns></returns>
		public override object GetAutomationObject()
		{
			if (null == automationObject)
			{
				automationObject = new OAWowFileItem(
					ProjectMgr.GetAutomationObject() as OAProject, this);
			}
			return automationObject;
		}

		/// <summary>
		/// Rename the underlying document based on the change the user just made to the edit label.
		/// </summary>
		/// <param name="label">New name of file.</param>
		/// <param name="relativePath"></param>
		protected internal override int SetEditLabel(string label, string relativePath)
		{
			int returnValue = base.SetEditLabel(label, relativePath);
			if (returnValue == VSConstants.S_OK)
			{
				try
				{
					string savePath = Path.GetDirectoryName(relativePath);
					if (!Path.IsPathRooted(relativePath))
					{
						savePath = Path.Combine(Path.GetDirectoryName(ProjectMgr.BaseURI.Uri.LocalPath), savePath);
					}
					RenameCodeFileReferences(Path.Combine(savePath, label));
				}
				catch (Exception e)
				{
					Trace.WriteLine(e);
				}
			}
			return returnValue;
		}


		/// <summary>
		/// Rename all childnodes and set new lua file name in Script node in FrameXml file.
		/// </summary>
		/// <param name="parentFileName">The node of renamed document.</param>
		private void RenameCodeFileReferences(string parentFileName)
		{
			FrameXmlMergerFactory mergerFactoryFactory;

			GetChildNodes().ForEach(
				child =>
					{
						var childNode = child as FileNode;
						if (null != childNode && IsLuaFile(child))
						{
							mergerFactoryFactory = new FrameXmlMergerFactory(ProjectMgr.Site);
							IFrameXmlMerger merger = mergerFactoryFactory.CreateMerger(parentFileName);
							merger.MergeFrameName(parentFileName, childNode.GetMkDocument());
						}
					});
		}

		#region  FileNode Helpers

		/// <summary>
		/// Determines whether [is lua file] [the specified file].
		/// </summary>
		/// <param name="file">The file.</param>
		/// <returns>
		/// 	<c>true</c> if [is lua file] [the specified file]; otherwise, <c>false</c>.
		/// </returns>
		private static bool IsLuaFile(HierarchyNode file)
		{
			return file.ItemNode.GetMetadata(ProjectFileConstants.SubType) == WowSubType.Code;
		}

		/// <summary>
		/// Gets the child nodes.
		/// </summary>
		/// <returns></returns>
		private List<HierarchyNode> GetChildNodes()
		{
			var childNodes = new List<HierarchyNode>();
			HierarchyNode childNode = FirstChild;
			while (childNode != null)
			{
				childNodes.Add(childNode);
				childNode = childNode.NextSibling;
			}
			return childNodes;
		}


		/// <summary>
		/// Gets the relative path.
		/// </summary>
		/// <returns></returns>
		public string GetRelativePath()
		{
			string relativePath = Path.GetFileName(ItemNode.GetMetadata(ProjectFileConstants.Include));
			HierarchyNode parent = Parent;
			while (parent != null && !(parent is ProjectNode))
			{
				relativePath = Path.Combine(parent.Caption, relativePath);
				parent = parent.Parent;
			}
			return relativePath;
		}

		#endregion

		/// <summary>
		/// Execs the command on node.
		/// </summary>
		/// <param name="guidCmdGroup">The GUID CMD group.</param>
		/// <param name="cmd">The CMD.</param>
		/// <param name="nCmdexecopt">The n cmdexecopt.</param>
		/// <param name="pvaIn">The pva in.</param>
		/// <param name="pvaOut">The pva out.</param>
		/// <returns></returns>
		protected override int ExecCommandOnNode(Guid guidCmdGroup, uint cmd, uint nCmdexecopt, IntPtr pvaIn,
		                                         IntPtr pvaOut)
		{
			if (ProjectMgr == null)
				throw new InvalidOperationException();

			return base.ExecCommandOnNode(guidCmdGroup, cmd, nCmdexecopt, pvaIn, pvaOut);
		}


		/// <summary>
		/// Return an state icon index
		/// </summary>
		/// <returns></returns>
		/// <summary>
		/// Sets the state icon for a file.
		/// </summary>
		//public override VsStateIcon StateIconIndex
		//{
		//    get
		//    {
		//        Trace.WriteLine("FileNode - StateIconIndex"); 
		//        if (!this.ExcludeNodeFromScc)
		//        {
		//            IVsSccManager2 sccManager = this.ProjectMgr.Site.GetService(typeof(SVsSccManager)) as IVsSccManager2;
		//            if (sccManager != null)
		//            {
		//                VsStateIcon[] statIcons = new VsStateIcon[1] { VsStateIcon.STATEICON_NOSTATEICON };
		//                uint[] sccStatus = new uint[1] { 0 };
		//                // Get the glyph from the scc manager. Note that it will fail in command line
		//                // scenarios.
		//                //if (ErrorHandler.Succeeded(sccManager.GetSccGlyph(1, new string[] { this.GetMkDocument() }, statIcons, sccStatus)))
		//                //{
		//                //    return statIcons[0];
		//                //}
		//                Trace.WriteLine(String.Format("IVsSccProvider: {0}", sccManager as IVsSccProvider));
		//                Trace.WriteLine(String.Format("sccManager: {0}", sccManager));
		//                Trace.WriteLine(String.Format("sccManager.GetHashCode: {0}", sccManager.GetHashCode()));
		//                int ret = sccManager.GetSccGlyph(1, new string[] {this.GetMkDocument()}, statIcons, sccStatus);
		//                Trace.WriteLine("statIcons: " + statIcons[0].ToString());
		//                Trace.WriteLine("sccStatus: " + sccStatus[0].ToString());
		//                Trace.WriteLine(String.Format("StateIconIndex Return: {0} [{1}]", (ret == VSConstants.S_OK).ToString(), ret));
		//                Trace.WriteLine(new string('-', 20));
		//                return statIcons[0];
		//            }
		//        }
		//        return VsStateIcon.STATEICON_NOSTATEICON;
		//    }
		//}
		//protected internal VSLangProj.VSProjectItem VSProjectItem
		//{
		//    get
		//    {
		//        if (null == vsProjectItem)
		//        {
		//            vsProjectItem = new OAVSProjectItem(this);
		//        }
		//        return vsProjectItem;
		//    }
		//}
		//protected internal Microsoft.Windows.Design.Host.DesignerContext DesignerContext
		//{
		//    get
		//    {
		//        if (designerContext == null)
		//        {
		//            designerContext = new DesignerContext();
		//        }
		//        return designerContext;
		//    }
		//}
		/// <summary>
		/// Returns bool indicating whether this node is of subtype "Form"
		///// </summary>
		//public bool IsFormSubType
		//{
		//    get
		//    {
		//        string result = this.ItemNode.GetMetadata(ProjectFileConstants.SubType);
		//        if (!String.IsNullOrEmpty(result) 
		//            && string.Compare(result, ProjectFileAttributeValue.Form, true, 
		//            CultureInfo.InvariantCulture) == 0)
		//            return true;
		//        else
		//            return false;
		//    }
		//}
		//internal override object Object
		//{
		//    get
		//    {
		//        return this.VSProjectItem;
		//    }
		//}
		/// <summary>
		/// Open a file depending on the SubType property associated with the file item in the project file
		/// </summary>
		//protected override void DoDefaultAction()
		//{
		//    FileDocumentManager manager = this.GetDocumentManager() as FileDocumentManager;
		//    Debug.Assert(manager != null, "Could not get the FileDocumentManager");
		//    Guid viewGuid = (IsFormSubType ? VSConstants.LOGVIEWID_Designer : VSConstants.LOGVIEWID_Code);
		//    IVsWindowFrame frame;
		//    manager.Open(false, false, viewGuid, out frame, WindowFrameShowAction.Show);
		//}
		/// <summary>
		/// Creates the services.
		/// </summary>
		/// <param name="serviceType">Type of the service.</param>
		/// <returns></returns>
		private object CreateServices(Type serviceType)
		{
			object service = typeof (ProjectItem) == serviceType
			                 	? GetAutomationObject()
			                 	: GetService(serviceType);
			return service;
		}


		/// <summary>
		/// Gets the service creator.
		/// </summary>
		/// <value>The service creator.</value>
		internal OleServiceProvider.ServiceCreatorCallback ServiceCreator
		{
			get { return CreateServices; }
		}
	}
}